home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / tex / files / !tex / TeXsource / beebe / c / old / dvialw next >
Encoding:
Text File  |  1990-05-18  |  55.6 KB  |  1,936 lines

  1. /* -*-C-*- dvialw.c */
  2. /*-->dvialw*/
  3. /**********************************************************************/
  4. /******************************* dvialw *******************************/
  5. /**********************************************************************/
  6.  
  7. #include "dvihead.h"
  8.  
  9. /***********************************************************************
  10. [23-Oct-87]    Modify output so that on  each page, fonts appear first,
  11.         followed  by   "save  ...text...   restore"   sequences.
  12.         Current  PostScript    implementations    on  commercial
  13.         printers  lack  garbage collection,  and strings consume
  14.         memory  even after printing.   The Apple LaserWriter and
  15.         LaserWriter Plus have  only  about 100Kb free for   each
  16.         job, which  at  current   memory   prices    is  grossly
  17.         inadequate.     Other PostScript  printer  vendors   are
  18.         offering substantially more memory.
  19.  
  20.         This feature is implemented not by time-consuming double
  21.         passes   through  the  DVI file, but    rather by having
  22.         setchar() and   setstr() buffer their output,   which is
  23.         dumped  (with bracketing save/restore   commands) either
  24.         when  the  buffer fills  up,   or when  end-of-page   is
  25.         reached.   A buffer of 8Kb is  adequate for this purpose
  26.         (based  on a 100-page document (dvidriver.ltx) producing
  27.         a  .dvi-alw file of  830Kb,   of  which  163Kb was  font
  28.         definitions,  giving  an  average  text  requirement  of
  29.         6.7Kb/page).  These  statistics were determined  on Unix
  30.         by
  31.  
  32.         awk '/^\[/,/^>/' foo.dvi-alw >foo.tmp
  33.         ls -l foo.*
  34.  
  35.         Awk extracts the font definitions into the file foo.tmp,
  36.         and ls tells how big the files  are.   A similar test on
  37.         pages  from the TeXBook  found some pages  needing up to
  38.         11Kb of text.
  39.  
  40.         Several new routines (putfontname(), text*()) and macros
  41.         (OUT_*) are introduced to support these  changes.   Some
  42.         care is needed when  introducing new  output sections to
  43.         call OUT_IMMEDIATE or  OUT_DEFERRED,  as appropropriate.
  44.         If this is  not done,  output  will  be in an  incorrect
  45.         order.
  46.  
  47.         Now that  almost   all output  flows  through  a  single
  48.         routine, textchr(), it is possible to monitor the output
  49.         to ensure   that lines do not   exceed   PS_WIDTH.  Text
  50.         output  for the \special{}  command   is an exception to
  51.         this  rule; it  is transmitted exactly  as found.   Long
  52.         comments are continued  with a trailing "-"  followed by
  53.         "%-" on the  next  line.   When textflush()  empties the
  54.         text buffer, newlines preceding "(" (the commonest case)
  55.         are  squeezed out,  as long as this does  not exceed the
  56.         line width limit.   Font   changes are shortened  to  F#
  57.         sequences, where # is the sequential number of  the font
  58.         (1,2,...) in the   dvi file.    F0  is reserved    for a
  59.         temporary font created inside a  save/restore pair for a
  60.         large character.
  61.  
  62.         Perhaps at some later  date, we could  sort the buffered
  63.         text by font type, and minimize font changing.
  64.  
  65. [10-Dec-86]    Fix off-by-one  error in  value  of y-offset  output  in
  66.         character definition  in loadchar();  this affects  only
  67.         the combination of rules with characters, such as  LaTeX
  68.         arrowheads.  No other DVI drivers are affected by this.
  69.  
  70.         Fix off-by-one error in size  of rule; this involves  no
  71.         code  change   here,  only   a  change   in   dvialw.ps.
  72.         Examination of output rules  under high power  magnifier
  73.         shows that to draw a rule of width N dots, the  bounding
  74.         box should have a width of N-1 dots; the boundary counts
  75.         toward the fill; this is  not clear from the  PostScript
  76.         manual.
  77.  
  78. [13-Jun-86]    Fix  special()--a  short  plot  file  could  result   in
  79.         infinite  loop  in  search  for  %%BoundingBox.    Fixed
  80.         openfont() to output requested magnification as well  as
  81.         substituted magnification.
  82.  
  83. [19-Apr-86]    Fix infinite  loop in  setstr(); BIGCHAR()  forced  exit
  84.         from character collection loop  on first iteration,  and
  85.         the current input  character was stuffed  back into  the
  86.         input buffer.    A  big character  should  just  suppress
  87.         downloading in the first loop.
  88.  
  89. [12-Mar-86]    Version 2.03  -- Major  overhaul of  PostScript  output.
  90.         Removed most explicit PostScript commands to header file
  91.         dvialw.ps (in current directory), or if unavailable, the
  92.         system  file  texinputs:dvialw.ps  (defined  by  symbols
  93.         PSDEF_PATH and PSDEF_FILE) which is copied to the output
  94.         file by new procedure  cppsfile(), stripped of  comments
  95.         and excess whitespace.  References  to these macros  are
  96.         output instead.   This  makes  parameter  twiddling  and
  97.         local customization much easier, and will allow users to
  98.         obtain a  variety of  page formats  and orientations  by
  99.         simple changes to  personal copies of  the header  file.
  100.         The header  file  is  heavily commented  and  should  be
  101.         referred to for macro descriptions and an outline of the
  102.         general PostScript document format produced by DVIALW.
  103.  
  104.         Removed variable-length  argument lists  to fatal()  and
  105.         warning() for  portability.   Changed  all  preprocessor
  106.         #ifdef's and  #ifndef's to  #if's for  portability;  all
  107.         symbols   for     devices,   operating     systems,    and
  108.         implementations are now explicitly defined to be 0 or 1.
  109.  
  110.         Added procedures fontfile() and fontsub() to encapsulate
  111.         construction of  system-dependent  font file  names  and
  112.         provide  for  user-specifiable  font  substitutions  for
  113.         unavailable font files.
  114.  
  115.         Fonts and character definitions are now encapsulated  in
  116.         compact macros.  With  help of Neal  Holtz's DVI2PS  and
  117.         TEX.PS, figured  out how  to  define fonts  with  origin
  118.         along baseline, allowing output of several characters in
  119.         a single command (except  where roundoff would make  TeX
  120.         and  PostScript  positions  disagree).     New   procedure
  121.         setstr() handles this.  Font scaling is now 1 for normal
  122.         output, but  can  be  changed  to  any  other  value  if
  123.         PostScript is to rescale the bitmaps (slow).  Tests show
  124.         a reduction  of about  20% in  total output  file  size.
  125.         When PS_SHORTLINES  is  defined, character  bitmaps  are
  126.         output one  scan line  per  line, making  them  somewhat
  127.         readable, and avoiding long lines.  Leaving them as  one
  128.         long line  could  reduce  the file  size  even  further.
  129.         Added support for LaTeX invisible  fonts; if you send  a
  130.         bitmap of size 0  by 0 to  the LaserWriter, all  further
  131.         fonts are printed as blanks  until you cycle the  power.
  132.         No character definitions are loaded for such fonts.
  133.  
  134.         Made reloading of fonts for each page an option "-v"; it
  135.         should now rarely be necessary.  With large manuscripts,
  136.         avoiding reloading cuts  the space by  60% or more,  and
  137.         seems to be  more successful at  printing, averaging  30
  138.         sec/page and  700-780 char/sec  (close to  limit of  960
  139.         char/sec from 9600 baud serial line).
  140.  
  141.         Removed old #ifdef  FOOBAR ... #endif  code sections  in
  142.         several  procedures  which  were  completely   obsolete.
  143.         Added header comment line to every file; it contains the
  144.         EMACS "-*-C-*-" mode string and the exact (case-sensive)
  145.         filename, since many  functions have  been defined  with
  146.         names in  mixed case  for readability  (probably  should
  147.         have used underscore instead, but none do), and on Unix,
  148.         the letter case matters.
  149.  
  150.         Replaced index()  and  rindex(),  which  have  different
  151.         definitions in  different C  implementations, by  4.2BSD
  152.         (and coming  ANSI  C standard)  functions  strchr()  and
  153.         strrchr(), for which .h files are provided.
  154.  
  155.         To further reduce the PostScript output size, PostScript
  156.         interactive mode experiments determined that spaces  are
  157.         not required  around parentheses,  brackets, or  braces,
  158.         but ARE necessary between  numbers and names.  Thus  the
  159.         sequences
  160.  
  161.         [ <hexstring> # # # # # ] # D
  162.         (string) # # S
  163.  
  164.         can be reduced to
  165.  
  166.         [<hexstring># # # # #]# D
  167.         (string)# # S
  168.  
  169.         saving 4 and 1 characters  respectively for each use  of
  170.         these commands.  The PostScript file copy utility, LW78,
  171.         already reduces CR LF pairs  to LF, so in the  interests
  172.         of editability,  we  retain  the  former.   Heavily-used
  173.         macros have  also  been  redefined  with  single  letter
  174.         names.
  175.  
  176. [18-Jan-86]    Version 2.02 -- Added macros  to define new fonts  (NF),
  177.         set fonts (SF),  and define characters  (CH) in  main.h,
  178.         and use  them  in  readfont.h  and  setchar().     Changed
  179.         setchar() to skip  character loading  when character  is
  180.         not  on  page.      Added  setstr()   to  output     several
  181.         characters at  a time,  instead of  using setchar()  for
  182.         each  of  them.   These  reduce  the  output  file  size
  183.         considerably.  Moved character  bitmap output code  into
  184.         loadchar() where it should have been in the first place.
  185.         Added test  for  output  errors  (usually  because  disk
  186.         storage is exhausted) in main.h and prtpage.h.
  187.  
  188. [20-Dec-85]    Following recommendation of Allan Hetzel on LASER-LOVERS
  189.         ARPA BBOARD, added "() pop" at top of every page.  This
  190.         selected by the switch PS_XONXOFFBUG:
  191.  
  192.         --------------------------------------------------------
  193.         From: Allan Hetzel  <SYSAL%UKCC.BITNET@WISCVM.ARPA>
  194.         Subject: Re: Apple Laserwriter XON/XOFF problem
  195.         To:  <LASER-LOVERS@WASHINGTON.ARPA>
  196.  
  197.         The note  posted to  Laser-Lovers on  Oct 28  by  Joseph
  198.         Goldstone of  Symbolics  Cambridge Research  Center  was
  199.         helpful but I didn't try his suggested fix correctly and
  200.         so I called Adobe.  They were very helpful (much more so
  201.         than Apple) and explained the problem and how to  bypass
  202.         it.
  203.  
  204.         My  apologies  to   Adobe  if  this   not  an    accurate
  205.         description of the problem.   The problem apparently  is
  206.         due to the  PostScript interpreter  getting confused  by
  207.         what it thinks is an excess of white space characters.
  208.  
  209.         The bypass is to place a special character (parenthesis,
  210.         bracket, brace, slash, etc.) to the right of some token,
  211.         but without an intervening white space character. As the
  212.         PostScript scanner  reads the  token it  also reads  the
  213.         special character which acts as a delimiter. The scanner
  214.         then has  to  back  up  one character  so  that  it  can
  215.         reprocess the special character  after it has  processed
  216.         the preceding token.  During  this backing up process  a
  217.         number of  internal values  are recalculated,  including
  218.         some pointer  into the  input buffer.    This causes  the
  219.         XON/XOFF protocol to work properly.  Doing this once per
  220.         page seems to keep everybody happy.
  221.  
  222.         Each page  in  the PostScript  file  built by  our  word
  223.         processing program  is surrounded  by a  "save  restore"
  224.         sequence.  We  changed     the  beginning  save    sequence
  225.         "/saveobj save def" to  read "/saveobj save def()  pop".
  226.         The "() pop" is effectively  a no-op and we are  assured
  227.         that the necessary recalculations are done on each page.
  228.         This seems to have corrected the problem completely.
  229.  
  230.         Allan Hetzel (sysal@ukcc.bitnet)
  231.         --------------------------------------------------------
  232. ***********************************************************************/
  233.  
  234. /**********************************************************************/
  235. /************************  Device Definitions  ************************/
  236. /**********************************************************************/
  237.  
  238. /* All output-device-specific definitions go here.  This section must
  239. be changed when modifying a dvi driver for use on a new device */
  240.  
  241. #undef POSTSCRIPT
  242. #define  POSTSCRIPT   1            /* conditional compilation flag */
  243.  
  244. #define PS_SIZELIMIT 150        /* characters larger than this */
  245.                     /* many dots high get loaded with */
  246.                     /* surrounding save/restore to */
  247.                     /* get around PostScript bugs */
  248.  
  249. #undef PS_XONXOFFBUG
  250. #define PS_XONXOFFBUG 1            /* Allen Hetzel's XON/XOFF bug fix */
  251.  
  252. #ifndef PS_SHORTLINES
  253. #define PS_SHORTLINES    0        /* run with long output lines */
  254. #endif
  255.  
  256. #define VERSION_NO    "2.10"        /* DVI driver version number */
  257.  
  258. #if    PS_XONXOFFBUG
  259. #undef VERSION_NO
  260. #define VERSION_NO    "2.10b"        /* DVI driver version number */
  261. #endif
  262.  
  263.  
  264. #define  DEVICE_ID    "PostScript [Apple LaserWriter laser printer]"
  265.                 /* this string is printed at runtime */
  266.  
  267. #define OUTFILE_EXT    "alw"
  268.  
  269. #define MAXPSLINE 80    /* longest line in PSDEF_FILE */
  270.  
  271. #define PSDEF_PATH subpath        /* pathname of system header file */
  272. #define PSDEF_FILE "dvialw.ps"        /* name of header file */
  273.  
  274. #define  BYTE_SIZE      7        /* output file byte size */
  275.  
  276. #undef STDRES
  277. #define STDRES  1            /* to get standard font resolution */
  278.  
  279. #undef MAXOPEN
  280. #define MAXOPEN 12            /* limit on number of open files */
  281.  
  282. #define  MAXLINE    4096        /* maximum input file line size */
  283.                     /* it is needed only in special() */
  284.  
  285. #define  XDPI        300        /* horizontal dots/inch */
  286. #define  XPSIZE        14        /* horizontal paper size in inches */
  287.                     /* (allow for landscape paper) */
  288. #define  XSIZE        (((XDPI*XPSIZE+2*HOST_WORD_SIZE-1)/\
  289.                 (2*HOST_WORD_SIZE))*(2*HOST_WORD_SIZE))
  290.                     /* number of horizontal dots; */
  291.                     /* MUST BE multiple of */
  292.                     /* 2*HOST_WORD_SIZE */
  293.  
  294. #define  YDPI        300        /* vertical dots/inch */
  295. #define  YPSIZE        11        /* vertical paper size in inches */
  296. #define  YSIZE        (YDPI*YPSIZE)    /* number of vertical dots */
  297.  
  298.  
  299. #if    PS_SHORTLINES
  300.  
  301. #ifndef PS_MAXWIDTH
  302. #define  PS_MAXWIDTH    72        /* output never exceeds this width */
  303. #endif
  304.  
  305. INT16    out_width;                     /* current line width */
  306.  
  307. #endif /* PS_SHORTLINES */
  308.  
  309. /***********************************************************************
  310. The following variables and macros implement the buffering of PostScript
  311. output  so  that output   size  can  be  reduced by    removing unneeded
  312. separators, and so that a maximum line width can be enforced, except for
  313. code from special{}, which must be output verbatim.
  314.  
  315. All PostScript output filters through textchr() at the lowest level, and
  316. on the basis of the `deferred' flag setting, it either defers  output of
  317. its  argument character by buffering  it in  textbuf[], or it outputs it
  318. immediately with putc().
  319.  
  320. Because  PostScript line  breaking  conventions are  context  sensitive,
  321. textchr() maintains static variables to  keep track  of the output state
  322. (comment,   text,  or  string).    It  also    handles all   end-of-line
  323. translations, so \n can be used for end-of-line everywhere else.
  324.  
  325. All  output  calls outside the  text*() routines are done through macros
  326. OUT_*,  and to  shorten coding,  OUT_NUM provides  a trailing delimiting
  327. space.
  328.  
  329. textbuf[] is allocated dynamically on the first call  to devinit() so as
  330. not to consume space in the executable program disk file.
  331.  
  332. textflush()  is  called by textchr()   when  textbuf[]  fills up, and by
  333. eopact() at end-of-page.
  334.  
  335. ***********************************************************************/
  336.  
  337. #define MAXTEXT        16384        /* size of textbuf[] buffer */
  338.  
  339. static char* textbuf = (char*)NULL;    /* buffer for setchar() and setstr() */
  340. static char* ptext;            /* next position in textbuf[] */
  341. static BOOLEAN deferred;        /* deferred output status flag */
  342. static UNSIGN16 last_font_number;     /* set by loadchar() */
  343.  
  344. #if    PS_SHORTLINES
  345. static BOOLEAN is_comment = FALSE;
  346. static BOOLEAN is_text = FALSE;
  347. static BOOLEAN is_string = FALSE;
  348. #endif /* PS_SHORTLINES */
  349.  
  350. #define OUT_CHR(c) textchr((char)c)
  351.  
  352. #define OUT_DEFERRED {deferred = TRUE;}
  353.  
  354. #define OUT_FLT(fmt,flt) {\
  355.     char s[25];\
  356.     (void)sprintf(s,fmt,flt);\
  357.     OUT_STR(s);}
  358.  
  359. #define OUT_FONTNAME {\
  360.     char s[11];\
  361.     (void)sprintf(s,"F%d",fontptr->font_number);\
  362.     OUT_STR(s);}
  363.  
  364. #define OUT_IMMEDIATE {deferred = FALSE;}
  365.  
  366. #define OUT_NL OUT_CHR('\n')
  367.  
  368. #define OUT_NUM(n) textnum((long)(n))
  369.  
  370. #define OUT_STR(s) textstr(s)
  371.  
  372. #define OUT_XCHR(c) emitchar(c)
  373.  
  374. #include "main.h"
  375. #include "abortrun.h"
  376. #include "actfact.h"
  377. #include "alldone.h"
  378.  
  379. /*-->bopact*/
  380. /**********************************************************************/
  381. /******************************* bopact *******************************/
  382. /**********************************************************************/
  383.  
  384. void
  385. bopact()            /* beginning of page action */
  386. {
  387.     INT16 page_number;        /* TeX's \count0 parameter            */
  388.  
  389.     page_number = (INT16)tex_counter[0];
  390.  
  391.     if (cur_page_number <= MAXPAGE)
  392.     {
  393.     (void)fflush(plotfp);
  394.     page_loc[cur_page_number] = (long)FTELL(plotfp);
  395.     page_tex[cur_page_number] = (INT32)page_number;
  396.     }
  397.     OUT_IMMEDIATE;
  398.     OUT_STR("%%Page: ");
  399.     OUT_NUM(page_number);
  400.     OUT_NUM(cur_page_number);
  401.     OUT_NL;
  402.     if (ps_vmbug)
  403.         OUT_STR("/SaveImage save def() pop\n");
  404.     OUT_STR("BOP\n");
  405.  
  406.     rule_height = -1;        /* reset last rule parameters */
  407.     rule_width = -1;
  408.     str_ycp = -1;        /* last string ycp */
  409. }
  410.  
  411. #include "chargf.h"
  412. #include "charpk.h"
  413. #include "charpxl.h"
  414. #include "clrrow.h"
  415.  
  416. /*-->cppsfile*/
  417. /**********************************************************************/
  418. /****************************** cppsfile ******************************/
  419. /**********************************************************************/
  420.  
  421. void
  422. cppsfile()        /* Copy PostScript header file to output */
  423. {            /* discarding comments and collapsing whitespace */
  424.     register int c;    /* input character */
  425.     register int k;    /* index in line[] */
  426.     FILE *psfp;        /* PostScript macro definition file */
  427.     char fname[MAXFNAME];
  428.     char line[MAXPSLINE+1];    /* extra space for NUL */
  429.  
  430.     /* Try private version of header file first, and if that fails, use */
  431.     /* system version.  Tell the user when a private version is selected. */
  432.  
  433.     OUT_IMMEDIATE;
  434.     (void)strcpy(fname,PSDEF_FILE);
  435.     psfp = fopen(fname,"r");
  436.     DEBUG_OPEN(psfp,fname,"r");
  437.     if (psfp == (FILE *)NULL)
  438.     {
  439.     (void)strcpy(fname,PSDEF_PATH);
  440.     (void)strcat(fname,PSDEF_FILE);
  441.     psfp = fopen(fname,"r");
  442.     DEBUG_OPEN(psfp,fname,"r");
  443.     if (psfp == (FILE *)NULL)
  444.     {
  445.         (void)sprintf(message,
  446.         "cppsfile():  Cannot open PostScript definition file [%s]",
  447.         fname);
  448.         (void)fatal(message);
  449.     }
  450.     }
  451.     else if (!quiet)
  452.     {
  453.     (void)fprintf(stderr,"[Using private PostScript definition file [%s]]",
  454.         fname);
  455.     NEWLINE(stderr);
  456.     }
  457.  
  458.     k = 0;
  459.     while ((c = getc(psfp)) != EOF)
  460.     {
  461.     if (c == '%')    /* flush comments to (but not including) end-of-line */
  462.     {
  463.         while (((c = getc(psfp)) != EOF) && (c != '\n'))
  464.         ;    /* flush to end-of-line or end-of-file */
  465.         c = '\n';    /* to force line output */
  466.         line[k++] = '\n';
  467.     }
  468.     else if ((c == ' ') || (c == '\t') || (c == '\f'))
  469.     {        /* have whitespace */
  470.         if (k)            /* then not at beginning of line */
  471.         line[k++] = ' ';    /* so save only one blank */
  472.         while (((c == ' ') || (c == '\t') || (c == '\f')) && (c != EOF))
  473.         c = getc(psfp);    /* discard following whitespace */
  474.         ungetc(c,psfp);    /* put back lookahead */
  475.     }
  476.     else if (c != '\r')    /* save all but CR */
  477.         line[k++] = (char)c;
  478.  
  479.     if ((c == '\n') || (c == EOF) || (k >= MAXPSLINE))
  480.     {
  481.         if (c == '\n')        /* discard LF */
  482.         k--;
  483.         while ((k > 0) && (line[k-1] == ' ')) /* and trailing blanks */
  484.         k--;
  485.         line[k] = '\0';
  486.         if (k > 0)    /* non-empty line */
  487.         {
  488.         OUT_STR(line);
  489.         OUT_NL;
  490.         }
  491.         k = 0;
  492.     }
  493.     }
  494.  
  495.     while ((k > 0) && (line[k-1] == ' '))    /* discard trailing blanks */
  496.     k--;
  497.     line[k] = '\0';
  498.     if (k > 0)    /* non-empty line */
  499.     {
  500.     OUT_STR(line);
  501.     OUT_NL;
  502.     }
  503.  
  504.     (void)fclose(psfp);
  505. }
  506.  
  507. #include "dbgopen.h"
  508.  
  509. /*-->devinit*/
  510. /**********************************************************************/
  511. /****************************** devinit *******************************/
  512. /**********************************************************************/
  513.  
  514. void
  515. devinit(argc,argv)        /* initialize device */
  516. int argc;
  517. char *argv[];
  518. {
  519.     register INT16 k;        /* loop index */
  520.     char timestring[26];    /* "wkd mon dd hh:mm:ss 19yy\n" */
  521.     long timeval;        /* clock value from time() for ctime()    */
  522.  
  523.     if (textbuf == (char*)NULL)
  524.     {                /* allocate textbuf[] only once */
  525.     textbuf = (char*)MALLOC((unsigned)(MAXTEXT+1));
  526.     if (textbuf == (char*)NULL)
  527.             (void)fatal("Cannot allocate memory for textbuf[]");
  528.     }
  529.  
  530.     ptext = textbuf;
  531.  
  532.     OUT_IMMEDIATE;        /* need immediate output here */
  533.     OUT_STR("%!\n");        /* magical file header */
  534.     OUT_STR("%%Dimensions: 0 0 612 792\n"); /* 8.5 x 11 inch page size */
  535.  
  536.     OUT_STR("%%Title: ");
  537.     OUT_STR(argv[0]);        /* start of our command line */
  538.     for (k = 1; k < (INT16)argc; ++k)
  539.     {
  540.     OUT_CHR(' ');
  541.     OUT_STR(argv[k]);
  542.     }
  543.     OUT_NL;            /* end of %%Title line */
  544.  
  545.     timeval = time((long*)NULL);
  546.     (void)strcpy(timestring,ctime(&timeval));
  547.     timestring[24] = '\0';    /* kill stupid \n from ctime() */
  548.  
  549.     OUT_STR("%%CreationDate: ");
  550.     OUT_STR(timestring);
  551.     OUT_NL;
  552.     OUT_STR("%%Creator: ");
  553.     OUT_STR((cuserid((char*)NULL) == (char*)NULL) ? "" : cuserid((char*)NULL));
  554.     OUT_STR(" and [TeX82 DVI Translator Version ");
  555.     OUT_STR(VERSION_NO);
  556.     OUT_STR(" for ");
  557.     OUT_STR(DEVICE_ID);
  558.     OUT_NL;
  559.  
  560.     OUT_STR("%%Pages: (atend)\n");
  561.  
  562.     if (ps_vmbug)
  563.     {
  564.     OUT_STR("%%BugHistory: Incorporates save/restore and font");
  565.     OUT_STR(" reloading for each page as PS Version 23.0");
  566.     OUT_STR(" \"VM error\" bug workaround\n");
  567.     }
  568.  
  569. #if    PS_XONXOFFBUG
  570.     OUT_STR("%%BugHistory: Incorporates Allan Hetzel\'s 31-Oct-85");
  571.     OUT_STR(" DARPA LASER-LOVERS PS Version 23.0 X-on/X-off");
  572.     OUT_STR(" bug workaround\n");
  573. #endif /* PS_XONXOFFBUG */
  574.  
  575.     OUT_STR("%%EndComments\n");
  576.     OUT_STR("%%EndProlog\n");
  577.     font_switched = TRUE;
  578.  
  579.     (void)cppsfile();    /* copy standard PostScript definitions */
  580.  
  581.     OUT_STR("TeXdict begin\n");
  582.     OUT_STR("BOJ\n");
  583.  
  584.     /* TB and TE (Text Begin and Text End) are save/restore sequences;
  585.        they are used when textflush() has to empty its current buffer. */
  586.  
  587.     OUT_STR("/TB {save} bdf\n");
  588.     OUT_STR("/TE {restore} bdf\n");
  589.  
  590. #if    0
  591.     OUT_STR("/TE {currentpoint 3 -1 roll restore moveto} bdf\n");
  592. #endif
  593.  
  594.     /* BB and BE (Big character Begin and End) are save/restore
  595.        sequences that create a temporary font and set a character
  596.        inside a save/restore pair. */
  597.     OUT_STR("/BB {save /F0 NF 1 /F0 SF} bdf\n");
  598.     OUT_STR("/BE {restore} bdf\n");
  599.  
  600.     font_count = 0;        /* no font numbers are assigned yet */
  601. }
  602.  
  603. /*-->devterm*/
  604. /**********************************************************************/
  605. /****************************** devterm *******************************/
  606. /**********************************************************************/
  607.  
  608. void
  609. devterm()            /* terminate device */
  610. {
  611.     register INT16 k;        /* loop index */
  612.  
  613.     OUT_IMMEDIATE;
  614.     OUT_STR("EOJ\n");
  615.     OUT_STR("%%Trailer\n");
  616.     OUT_STR("%%Pages: ");
  617.     OUT_NUM(page_count);
  618.     OUT_NL;
  619.     OUT_STR("%%PageTable: ");
  620.  
  621.     for (k = 1; k <= MIN(MAXPAGE,cur_page_number); ++k)
  622.     {
  623.     OUT_NUM(page_tex[k]);
  624.     OUT_NUM(k);
  625.     OUT_NUM(page_loc[k]);
  626.     }
  627.  
  628.     OUT_NL;
  629.     OUT_CHR('\004');        /* PostScript end-of-job signal */
  630. }
  631.  
  632. #include "dvifile.h"
  633. #include "dviinit.h"
  634. #include "dviterm.h"
  635.  
  636. /*-->emitchar*/
  637. /**********************************************************************/
  638. /****************************** emitchar ******************************/
  639. /**********************************************************************/
  640.  
  641. void
  642. emitchar(c)                /* output string character with */
  643. register BYTE c;            /* escapes and octal as necessary */
  644. {
  645.  
  646.     /* we do our own octal formatting for speed */
  647.     static char octalchars[] = "01234567";
  648.  
  649. #define OCTAL(b) octalchars[((b) & 07)]
  650.  
  651. #if    PS_SHORTLINES
  652.     if (!deferred && ((out_width + 4) >= (PS_MAXWIDTH-1)))
  653.     {
  654.         OUT_CHR('\\');                     /* PostScript ignores */
  655.         OUT_NL;                /* backslash-newline sequences */
  656.     }
  657. #endif /* PS_SHORTLINES */
  658.  
  659.     if (isprint(c) &&
  660.     /* [textchr() requires the following restrictions] */
  661.         !((c == ' ' ) || (c == '%') || (c == '(') || (c == ')') ||
  662.        (c == '<') || (c == '>'))) /* character is printable */
  663.     {
  664.     if (c == '\\')        /* double backslashes */
  665.         OUT_CHR('\\');
  666.     OUT_CHR(c);
  667.     }
  668.     else                /* use octal form */
  669.     {
  670.     OUT_CHR('\\');
  671.     OUT_CHR(OCTAL(c >> 6));
  672.     OUT_CHR(OCTAL(c >> 3));
  673.     OUT_CHR(OCTAL(c));
  674.     }
  675. }
  676.  
  677. /*-->eopact*/
  678. /**********************************************************************/
  679. /******************************* eopact *******************************/
  680. /**********************************************************************/
  681.  
  682. void
  683. eopact()            /* end of page action */
  684. {
  685.     register INT32 k;        /* loop index */
  686.  
  687.     textflush();        /* output accumulated text */
  688.     OUT_IMMEDIATE;
  689.     OUT_NUM(copies);
  690.     OUT_STR("EOP\n");
  691.  
  692.     if (ps_vmbug)
  693.     {
  694.     OUT_STR("SaveImage restore() pop\n");
  695.     font_switched = TRUE;
  696.     fontptr = hfontptr;
  697.     while (fontptr != (struct font_entry *)NULL)
  698.     {
  699.         for (k = 0; k < NPXLCHARS; ++k)
  700.         fontptr->ch[k].isloaded = FALSE;
  701.         fontptr = fontptr->next;
  702.     }
  703.     }
  704.  
  705.     for (k = (INT32)copies; k; --k)
  706.         OUTC('\f');        /* FF's for simple page accounting */
  707. }
  708.  
  709. #include "f20open.h"
  710. #include "fatal.h"
  711.  
  712. /*-->fillrect*/
  713. /**********************************************************************/
  714. /****************************** fillrect ******************************/
  715. /**********************************************************************/
  716.  
  717. void
  718. fillrect(x,y,width,height)
  719. COORDINATE x,y,width,height;        /* lower left corner, size */
  720.  
  721. /***********************************************************************
  722. With the  page origin  (0,0) at  the lower-left  corner, draw  a  filled
  723. rectangle at (x,y).
  724.  
  725. For most  TeX  uses, rules  are  uncommon, and  little  optimization  is
  726. possible.  However, for the LaTeX Bezier option, curves are simulated by
  727. many small rules (typically  2 x 2)  separated by positioning  commands.
  728. By remembering  the size  of the  last rule  set, we  can test  for  the
  729. occurrence of repeated rules of the same size, and reduce the output  by
  730. omitting the rule  sizes.  The  last rule  parameters are  reset by  the
  731. begin-page action in prtpage(), so they do not carry across pages.
  732.  
  733. It is not possible to use relative, instead of absolute, moves in  these
  734. sequences, without stacking rules for the whole page, because each  rule
  735. is separated in  the DVI file  by push, pop,  and positioning  commands,
  736. making  for  an  uncertain  correspondence  between  internal  (xcp,ycp)
  737. pixel page coordinates and external device coordinates.
  738. ***********************************************************************/
  739.  
  740. {
  741.     str_ycp = -1;        /* invalidate string y coordinate */
  742.  
  743.     OUT_IMMEDIATE;        /* because Q uses width and height saved */
  744.     OUT_NUM(x);            /* by B, we cannot use deferred output; */
  745.     OUT_NUM(y);            /* otherwise a TB B TE TB Q TE would fail */
  746.     if ((height != rule_height) || (width != rule_width))
  747.     {
  748.     OUT_CHR('M');
  749.     OUT_CHR(' ');
  750.     OUT_NUM(width);
  751.     OUT_NUM(height);
  752.     OUT_CHR('B');
  753.     OUT_CHR(' ');
  754.     rule_width = width;    /* save current rule parameters */
  755.     rule_height = height;
  756.     }
  757.     else
  758.     {
  759.     OUT_CHR('Q');
  760.     OUT_CHR(' ');
  761.     }
  762. }
  763.  
  764. #include "findpost.h"
  765. #include "fixpos.h"
  766. #include "fontfile.h"
  767. #include "fontsub.h"
  768. #include "getbytes.h"
  769. #include "getfntdf.h"
  770. #include "getpgtab.h"
  771. #include "inch.h"
  772. #include "initglob.h"
  773.  
  774. /*-->loadchar*/
  775. /**********************************************************************/
  776. /****************************** loadchar ******************************/
  777. /**********************************************************************/
  778.  
  779. void
  780. loadchar(c)
  781. register BYTE c;
  782. {
  783.     void (*charyy)();        /* subterfuge to get around PCC-20 bug */
  784.     register struct char_entry *tcharptr; /* temporary char_entry pointer */
  785.  
  786.     if ((c < FIRSTPXLCHAR) || (LASTPXLCHAR < c)) /* check character range */
  787.     return;
  788.  
  789.     tcharptr = &(fontptr->ch[c]);
  790.  
  791.     if (!VISIBLE(tcharptr))
  792.     return;                /* do nothing for invisible fonts */
  793.  
  794.     if (fontptr != pfontptr)
  795.     openfont(fontptr->n);
  796.  
  797.     if (fontfp == (FILE *)NULL)        /* do nothing if no font file */
  798.     return;
  799.  
  800.     tcharptr->isloaded = TRUE;
  801.  
  802.     clearerr(plotfp);        /* VMS sets the error flag unexpectedly */
  803.  
  804.     OUT_IMMEDIATE;
  805.     OUT_STR("[<");
  806.  
  807.     /* Bug workaround: PCC-20 otherwise jumps to charxx instead of *charxx */
  808.     charyy = fontptr->charxx;
  809.     (void)(*charyy)(c,outrow);        /* output rasters */
  810.  
  811.     OUT_CHR('>');
  812.     OUT_NUM(tcharptr->xoffp);
  813.     OUT_NUM((tcharptr->yoffp)+1);
  814.     OUT_NUM(tcharptr->wp);
  815.     OUT_NUM(tcharptr->hp);
  816.     OUT_FLT("%.7f]",(float)(tcharptr->tfmw)*conv)
  817.     OUT_NUM(c);
  818.     OUT_CHR('D');
  819.  
  820. #if    PS_SHORTLINES
  821.     OUT_CHR(' ');
  822. #else
  823.     OUT_NL;
  824. #endif /* PS_SHORTLINES */
  825.  
  826.     /* Because of the deferred output feature, we now need to remember
  827.        the last font used, so on the next call, we know whether to
  828.        issue another OUT_FONTNAME or not.  font_switched is no longer
  829.        sufficient.
  830.     */
  831.     last_font_number = fontptr->font_number;
  832.  
  833.     if (DISKFULL(plotfp))
  834.     (void)fatal("loadchar():  Output error -- disk storage probably full");
  835. }
  836.  
  837.  
  838. #include "movedown.h"
  839. #include "moveover.h"
  840. #include "moveto.h"
  841.  
  842. /*-->newfont*/
  843. /**********************************************************************/
  844. /****************************** newfont *******************************/
  845. /**********************************************************************/
  846.  
  847. void
  848. newfont()
  849. {
  850.     register UNSIGN16 the_char;    /* loop index */
  851.     char s[MAXSTR];
  852.  
  853.     for (the_char = FIRSTPXLCHAR; the_char <= LASTPXLCHAR; the_char++)
  854.     fontptr->ch[the_char].isloaded = FALSE;
  855.  
  856.     font_count++;
  857.     fontptr->font_number = font_count;
  858.  
  859.     OUT_IMMEDIATE;
  860.  
  861.     (void)sprintf(s,"/%s NF %% %s\n",putfontname(fontptr),
  862.           fontptr->name);
  863.     OUT_STR(s);    /* declare new font for PostScript */
  864.  
  865.     (void)sprintf(s,"/F%d {1 /%s SF} bdf\n",
  866.           fontptr->font_number,putfontname(fontptr));
  867.     OUT_STR(s);    /* compact shorthand for font changes */
  868. }
  869.  
  870. #include "nosignex.h"
  871. #include "openfont.h"
  872. #include "option.h"
  873.  
  874. /*-->outrow*/
  875. /**********************************************************************/
  876. /******************************* outrow *******************************/
  877. /**********************************************************************/
  878.  
  879. void
  880. outrow(c,yoff)    /* output img_row[] to device */
  881. BYTE c;        /* current character value */
  882. UNSIGN16 yoff;    /* offset from top row (0,1,...,hp-1) (UNUSED here) */
  883. {
  884.     UNSIGN16 bytes_per_row;    /* number of raster bytes to copy */
  885.     register UNSIGN16 k;    /* loop index */
  886.     register UNSIGN32 *p;    /* pointer into img_row[] */
  887.     struct char_entry *tcharptr;/* temporary char_entry pointer */
  888.     register BYTE the_byte;    /* unpacked raster byte */
  889.  
  890.     /* we do our own hexadecimal formatting for speed */
  891.     static char hexchars[] = "0123456789ABCDEF";
  892.  
  893. #define NIBBLE(b) hexchars[(b) & 0x0f]
  894.  
  895.     tcharptr = &(fontptr->ch[c]); /* assume check for valid c has been done */
  896.     bytes_per_row = (UNSIGN16)((tcharptr->wp) + 7) >> 3; /* wp div 8 */
  897.     p = img_row;        /* we step pointer p along img_row[] */
  898.  
  899.     for (k = bytes_per_row; k > 0; ++p)
  900.     {
  901.  
  902.     the_byte = (BYTE)((*p) >> 24);
  903.     OUT_CHR(NIBBLE(the_byte>>4));
  904.     OUT_CHR(NIBBLE(the_byte));
  905.     if ((--k) <= 0)
  906.         break;
  907.  
  908.     the_byte = (BYTE)((*p) >> 16);
  909.     OUT_CHR(NIBBLE(the_byte>>4));
  910.     OUT_CHR(NIBBLE(the_byte));
  911.     if ((--k) <= 0)
  912.         break;
  913.  
  914.     the_byte = (BYTE)((*p) >> 8);
  915.     OUT_CHR(NIBBLE(the_byte>>4));
  916.     OUT_CHR(NIBBLE(the_byte));
  917.     if ((--k) <= 0)
  918.         break;
  919.  
  920.     the_byte = (BYTE)(*p);
  921.     OUT_CHR(NIBBLE(the_byte>>4));
  922.     OUT_CHR(NIBBLE(the_byte));
  923.     if ((--k) <= 0)
  924.         break;
  925.     }
  926.  
  927. #if    PS_SHORTLINES
  928.     /* line breaking handled by textchr() */
  929. #else
  930.     k = 40 / MAX(1,bytes_per_row); /* rows per 80-character line */
  931.     /* break after last row, or whenever an 80-character line has
  932.        been filled up */
  933.     if (((yoff+1) == tcharptr->hp) || (((yoff+1) % k) == 0))
  934.         OUT_NL;
  935. #endif /* PS_SHORTLINES */
  936.  
  937. }
  938.  
  939. #include "prtpage.h"
  940.  
  941. /*-->putfontname*/
  942. /**********************************************************************/
  943. /**************************** putfontname *****************************/
  944. /**********************************************************************/
  945.  
  946. char*
  947. putfontname(font_ptr)
  948. register struct font_entry *font_ptr;
  949. /* Output TeX font name and magnification in form "cmr10_1500" as a
  950. unique PostScript font identifier */
  951. {
  952.     register char* nameptr;
  953.     register char* p;
  954.     static char namebuf[MAXSTR];
  955.  
  956.     nameptr = &(font_ptr->n[0]);
  957.     p = namebuf;
  958.  
  959.     while (*nameptr)    /* make name with non-alphanumerics  */
  960.     {            /* changed to underscore for PostScript */
  961.     *p++ = isalnum(*nameptr) ? *nameptr : '_';
  962.     nameptr++;
  963.     }
  964.  
  965.     (void)sprintf(p,"_%d",(int)font_ptr->magnification);
  966.  
  967.     return (&namebuf[0]);
  968. }
  969.  
  970. #include "readfont.h"
  971. #include "readgf.h"
  972. #include "readpk.h"
  973. #include "readpost.h"
  974. #include "readpxl.h"
  975. #include "reldfont.h"
  976. #include "rulepxl.h"
  977.  
  978. /*-->setchar*/
  979. /**********************************************************************/
  980. /****************************** setchar *******************************/
  981. /**********************************************************************/
  982.  
  983. void
  984. setchar(c, update_h)
  985. register BYTE c;
  986. register BOOLEAN update_h;
  987. {
  988.     register struct char_entry *tcharptr;  /* temporary char_entry pointer */
  989.  
  990.     /* BIGCHAR() and ONPAGE() are used here and in setstr() */
  991.  
  992. #define BIGCHAR(t) ((t->wp > (COORDINATE)size_limit) ||\
  993.     (t->hp > (COORDINATE)size_limit))
  994.  
  995. #define ONPAGE(t) (((hh - t->xoffp + t->pxlw) <= XSIZE) \
  996.     && (hh >= 0)\
  997.     && (vv <= YSIZE)\
  998.     && (vv >= 0))
  999.  
  1000.     if (DBGOPT(DBG_SET_TEXT))
  1001.     {
  1002.     (void)fprintf(stderr,"setchar('");
  1003.     if (isprint(c))
  1004.         (void)putc(c,stderr);
  1005.     else
  1006.         (void)fprintf(stderr,"\\%03o",(int)c);
  1007.     (void)fprintf(stderr,"'<%d>) (hh,vv) = (%ld,%ld) font name <%s>",
  1008.         (int)c, (long)hh, (long)vv, fontptr->n);
  1009.     NEWLINE(stderr);
  1010.     }
  1011.  
  1012.     tcharptr = &(fontptr->ch[c]);
  1013.  
  1014.     moveto(hh,YSIZE-vv);
  1015.     if (ONPAGE(tcharptr))
  1016.     {                /* character fits entirely on page */
  1017.     if (VISIBLE(tcharptr))
  1018.     {
  1019.         if (BIGCHAR(tcharptr))
  1020.         {
  1021.         /* always need absolute coordinates (save/restore causes */
  1022.         /* loss of updated position) */
  1023.         OUT_IMMEDIATE;
  1024.  
  1025. #if    PS_SHORTLINES
  1026.         /* line breaking handled by textchar() */
  1027. #else
  1028.         OUT_NL;
  1029. #endif /* PS_SHORTLINES */
  1030.  
  1031.         OUT_STR("BB");
  1032.  
  1033. #if    PS_SHORTLINES
  1034.         OUT_CHR(' ');
  1035. #else
  1036.         OUT_NL;
  1037. #endif /* PS_SHORTLINES */
  1038.  
  1039.         loadchar(c);
  1040.         OUT_CHR('(');
  1041.         OUT_XCHR(c);
  1042.         OUT_CHR(')');
  1043.         OUT_NUM(xcp);
  1044.         OUT_NUM(ycp);
  1045.         OUT_CHR('S');
  1046.  
  1047. #if    PS_SHORTLINES
  1048.         OUT_CHR(' ');
  1049. #else
  1050.         OUT_NL;
  1051. #endif /* PS_SHORTLINES */
  1052.  
  1053.         OUT_STR("BE");
  1054.  
  1055. #if    PS_SHORTLINES
  1056.         /* line breaking handled by textchar() */
  1057. #else
  1058.         OUT_NL;
  1059. #endif /* PS_SHORTLINES */
  1060.  
  1061.         tcharptr->isloaded = FALSE;    /* 'unload' character */
  1062.         }
  1063.         else
  1064.         {
  1065.         if (!tcharptr->isloaded)
  1066.         {
  1067.             if ((font_switched) ||
  1068.             (fontptr->font_number != last_font_number))
  1069.             {
  1070.             OUT_IMMEDIATE;
  1071.             OUT_FONTNAME;
  1072.             }
  1073.             loadchar(c);
  1074.         }
  1075.         OUT_DEFERRED;
  1076.         if (font_switched)
  1077.         {
  1078.             OUT_FONTNAME;
  1079.             font_switched = FALSE;
  1080.         }
  1081.         OUT_CHR('(');
  1082.         OUT_XCHR(c);
  1083.         OUT_CHR(')');
  1084.         if (ycp != str_ycp)
  1085.         {
  1086.             OUT_NUM(xcp);
  1087.             OUT_NUM(ycp);
  1088.             OUT_STR("S\n");
  1089.             str_ycp = ycp;
  1090.         }
  1091.         else
  1092.         {
  1093.             OUT_NUM(xcp);
  1094.             OUT_STR("T\n");
  1095.         }
  1096.         }
  1097.  
  1098.     }
  1099.     }
  1100.     else if (DBGOPT(DBG_OFF_PAGE) && !quiet)
  1101.     {                /* character is off page -- discard it */
  1102.     (void)fprintf(stderr,
  1103.         "setchar(): Char %c [10#%3d 8#%03o 16#%02x] off page.",
  1104.         isprint(c) ? c : '?',c,c,c);
  1105.     NEWLINE(stderr);
  1106.     }
  1107.  
  1108.     if (update_h)
  1109.     {
  1110.     h += (INT32)tcharptr->tfmw;
  1111.     hh += (COORDINATE)tcharptr->pxlw;
  1112.     hh = fixpos(hh-lmargin,h,conv) + lmargin;
  1113.     }
  1114. }
  1115.  
  1116. #include "setfntnm.h"
  1117. #include "setrule.h"
  1118.  
  1119. /*-->setstr*/
  1120. /**********************************************************************/
  1121. /******************************* setstr *******************************/
  1122. /**********************************************************************/
  1123.  
  1124. void
  1125. setstr(c)
  1126. register BYTE c;
  1127. {
  1128.     register struct char_entry *tcharptr;  /* temporary char_entry pointer */
  1129.     register BOOLEAN inside;
  1130.     COORDINATE xcp_start,ycp_start;    /* starting coordinates of string */
  1131.     INT32 h0,v0;        /* (h,v) at entry */
  1132.     COORDINATE hh0,vv0;        /* (hh,vv) at entry */
  1133.     register UNSIGN16 k;    /* loop index */
  1134.     UNSIGN16 maxstr;        /* loop limit */
  1135.     UNSIGN16 nstr;        /* number of characters in str[] */
  1136.     BOOLEAN save_font_switched;    /* for saving font_switched value */
  1137.     BYTE str[MAXSTR+1];        /* string accumulator */
  1138.     BOOLEAN truncated;        /* off-page string truncation flag */
  1139.  
  1140.     /*******************************************************************
  1141.     Set a sequence of characters in SETC_000 .. SETC_127 with a  minimal
  1142.     number of PostScript print-string commands.  These sequences tend to
  1143.     occur in  long clumps  in  a DVI  file,  and setting  them  together
  1144.     whenever possible  substantially decreases  the PostScript  overhead
  1145.     and the size of the output file.  A sequence can be set as a  single
  1146.     string if
  1147.  
  1148.     * TeX and PostScript coordinates of each character agree (always
  1149.       true since  PostScript  has  high-precision  character  widths
  1150.       available;  for  non-PostScript  devices,  violation  of  this
  1151.       requirement can be detected if fixpos() changes hh, or if  ycp
  1152.       != ycp_start), AND
  1153.  
  1154.     * each character is in the same font (this will always be true
  1155.       in a sequence from a DVI file), AND
  1156.  
  1157.     * each character fits within the page boundaries, AND
  1158.  
  1159.     * each character definition is already loaded, AND
  1160.  
  1161.     * each character is from a visible font, AND
  1162.  
  1163.     * each  character bitmap  extent is smaller  than the size_limit
  1164.       (which is  used to  enable discarding  large characters  after
  1165.       each use in order  to conserve virtual  memory storage on  the
  1166.       output device).
  1167.  
  1168.     Whenever any of these conditions  does not hold, any string  already
  1169.     output is terminated, and a new one begun.  In order to avoid output
  1170.     of empty  string requests,  a flag  "inside" is  set when  a  string
  1171.     opener "(" is output, and unset when the string terminator ") x y S"
  1172.     or ") P" is output.
  1173.  
  1174.     Two output optimizations are implemented here.  First, up to  MAXSTR
  1175.     (in practice more  than enough) characters  are collected in  str[],
  1176.     and any  that  require downloading  are  handled.  Then  the  entire
  1177.     string is set at once, subject to the above limitations.  Second, by
  1178.     recording the vertical page coordinate, ycp, in the global  variable
  1179.     str_ycp  (reset  in  prtpage()  at  begin-page  processing),  it  is
  1180.     possible to avoid  outputting y coordinates  unnecessarily, since  a
  1181.     single line of  text will  generally result  in many  calls to  this
  1182.     function.
  1183.     *******************************************************************/
  1184.  
  1185. #define BEGINSTRING {inside = TRUE;\
  1186.     xcp_start = xcp;\
  1187.     ycp_start = ycp;\
  1188.     OUT_CHR('(');}
  1189.  
  1190. #define ENDSTRING {inside = FALSE;\
  1191.     OUT_CHR(')');\
  1192.     if (ycp == str_ycp)\
  1193.     {\
  1194.         OUT_NUM(xcp_start);\
  1195.         OUT_STR("T\n");\
  1196.     }\
  1197.     else\
  1198.     {\
  1199.         OUT_NUM(xcp_start);\
  1200.         OUT_NUM(ycp_start);\
  1201.         OUT_STR("S\n");\
  1202.     str_ycp = ycp;\
  1203.     }}
  1204.  
  1205. #define OFF_PAGE (-32767)    /* off-page coordinate value */
  1206.  
  1207.     inside = FALSE;
  1208.     truncated = FALSE;
  1209.     OUT_IMMEDIATE;
  1210.  
  1211.     hh0 = hh;
  1212.     vv0 = vv;
  1213.     h0 = h;
  1214.     v0 = v;
  1215.     save_font_switched = font_switched;
  1216.     nstr = 0;
  1217.  
  1218. #if    PS_SHORTLINES
  1219.     /* With deferred output, textflush() cannot do any output parsing,
  1220.        so to avoid long lines, we allow at most a string
  1221.        "(...)nnnnn nnnnn S" on one line. */
  1222.     maxstr = MIN(PS_MAXWIDTH-15,MAXSTR);
  1223. #else
  1224.     maxstr = MAXSTR;
  1225. #endif /* PS_SHORTLINES */
  1226.  
  1227.     while ((SETC_000 <= c) && (c <= SETC_127) && (nstr < maxstr))
  1228.     {   /* collect character sequence and download needed fonts */
  1229.     tcharptr = &(fontptr->ch[c]);
  1230.  
  1231.     moveto(hh,YSIZE-vv);
  1232.  
  1233.     if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
  1234.     {        /* character fits entirely on page and is visible */
  1235.         if ((!tcharptr->isloaded) && (!BIGCHAR(tcharptr)))
  1236.         {
  1237.         if (font_switched ||
  1238.             (fontptr->font_number != last_font_number))
  1239.         {
  1240.             OUT_FONTNAME;
  1241.             font_switched = FALSE;
  1242.         }
  1243.         loadchar(c);
  1244.         }
  1245.     }
  1246.     /* update horizontal positions in TFM and pixel units */
  1247.     h += (INT32)tcharptr->tfmw;
  1248.     hh += (COORDINATE)tcharptr->pxlw;
  1249.     hh = fixpos(hh-lmargin,h,conv) + lmargin;
  1250.  
  1251.     str[nstr++] = c;        /* save string character */
  1252.  
  1253.     c = (BYTE)nosignex(dvifp,(BYTE)1);
  1254.     }
  1255.  
  1256.     /* put back character which terminated the loop */
  1257.     (void)UNGETC((int)(c),dvifp);
  1258.  
  1259.     hh = hh0;            /* restore coordinates at entry */
  1260.     vv = vv0;
  1261.     h = h0;
  1262.     v = v0;
  1263.  
  1264.     if (DBGOPT(DBG_SET_TEXT))
  1265.     {
  1266.     (void)fprintf(stderr,"setstr(\"");
  1267.     for (k = 0; k < nstr; ++k)
  1268.     {
  1269.         c = str[k];
  1270.         if (isprint(c))
  1271.             (void)putc(c,stderr);
  1272.         else
  1273.             (void)fprintf(stderr,"\\%03o",(int)c);
  1274.     }
  1275.     (void)fprintf(stderr,"\") (hh,vv) = (%ld,%ld) font name <%s>",
  1276.         (long)hh, (long)vv, fontptr->n);
  1277.     NEWLINE(stderr);
  1278.     }
  1279.  
  1280.     OUT_DEFERRED;
  1281.     font_switched = save_font_switched;
  1282.     if (font_switched)
  1283.     {
  1284.     OUT_FONTNAME;
  1285.     OUT_NL;            /* string might not be visible */
  1286.     font_switched = FALSE;
  1287.     }
  1288.  
  1289.     for (k = 0; k < nstr; ++k)
  1290.     {   /* now set the collected characters */
  1291.     c = str[k];
  1292.     tcharptr = &(fontptr->ch[c]);
  1293.     moveto(hh,YSIZE-vv);
  1294.  
  1295.     if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
  1296.     {        /* character fits entirely on page and is visible */
  1297.         if (tcharptr->isloaded) /* character already downloaded */
  1298.         {
  1299.         if (!inside)
  1300.             BEGINSTRING;
  1301.         OUT_XCHR(c);
  1302.         }
  1303.         else /* must be big character (others are already downloaded) */
  1304.         {
  1305.         if (inside)
  1306.             ENDSTRING;        /* finish any open string */
  1307.         if (BIGCHAR(tcharptr))
  1308.         {    /* Large character to be discarded. */
  1309.             /* Inside save/restore, updated current point */
  1310.             /* is lost, so we must force absolute positioning */
  1311.                 /* by resetting str_ycp before and after setting */
  1312.             /* the character. */
  1313.             str_ycp = OFF_PAGE;
  1314.             OUT_IMMEDIATE;
  1315.  
  1316. #if    PS_SHORTLINES
  1317.         /* line breaking handled by textchar() */
  1318. #else
  1319.             OUT_NL;
  1320. #endif /* PS_SHORTLINES */
  1321.  
  1322.                     OUT_STR("BB");
  1323.  
  1324. #if    PS_SHORTLINES
  1325.             OUT_CHR(' ');
  1326. #else
  1327.             OUT_NL;
  1328. #endif /* PS_SHORTLINES */
  1329.  
  1330.             loadchar(c);
  1331.             BEGINSTRING;
  1332.             OUT_XCHR(c);
  1333.             ENDSTRING;
  1334.             OUT_STR("BE");
  1335.  
  1336. #if    PS_SHORTLINES
  1337.             OUT_CHR(' ');
  1338. #else
  1339.             OUT_NL;
  1340. #endif /* PS_SHORTLINES */
  1341.  
  1342.             OUT_CHR(' ');
  1343.             OUT_DEFERRED;
  1344.             tcharptr->isloaded = FALSE;    /* 'unload' character */
  1345.             str_ycp = OFF_PAGE;
  1346.         }
  1347.         }
  1348.     }
  1349.     else        /* character does not fit on page -- output */
  1350.     {        /* current string and discard the character */
  1351.         truncated = TRUE;
  1352.         if (inside)
  1353.         ENDSTRING;
  1354.     }
  1355.     /* update horizontal positions in TFM and pixel units */
  1356.     h += (INT32)tcharptr->tfmw;
  1357.     hh += (COORDINATE)tcharptr->pxlw;
  1358.     hh = fixpos(hh-lmargin,h,conv) + lmargin;
  1359.     }
  1360.     if (truncated && DBGOPT(DBG_OFF_PAGE) && !quiet)
  1361.     {
  1362.     (void)fprintf(stderr,"setstr(): Text [");
  1363.     for (k = 0; k < nstr; ++k)
  1364.         (void)fprintf(stderr,isprint(str[k]) ? "%c" : "\\%03o",str[k]);
  1365.     (void)fprintf(stderr,"] truncated at page boundaries.");
  1366.     NEWLINE(stderr);
  1367.     }
  1368.  
  1369.     if (inside)        /* finish last string */
  1370.     ENDSTRING;
  1371. }
  1372.  
  1373. #include "signex.h"
  1374. #include "skgfspec.h"
  1375. #include "skipfont.h"
  1376. #include "skpkspec.h"
  1377.  
  1378. /*-->special*/
  1379. /**********************************************************************/
  1380. /****************************** special *******************************/
  1381. /**********************************************************************/
  1382.  
  1383. void
  1384. special(s)            /* process TeX \special{} string in s[] */
  1385. register char *s;
  1386. {
  1387.     char line[MAXLINE+2];
  1388.     FILE *specfile;
  1389.     BOOLEAN abspos;
  1390.     INT16 k;
  1391.     int llx,lly,urx,ury;        /* must be int for sscanf() */
  1392.     struct stat statbuf;        /* so fstat() can get file size */
  1393.  
  1394. /***********************************************************************
  1395. The TeX \special{} command is expected to look like
  1396.  
  1397.     \special{overlay filename}        % absolute positioning
  1398.     or
  1399.     \special{include filename}        % relative positioning
  1400.     or
  1401.     \special{insert filename}        % relative positioning
  1402.  
  1403. In the first  case, the PostScript  file to be  included will be  mapped
  1404. onto the page at precisely the  coordinates it specifies.  In the  other
  1405. two cases, the upper-left corner of  the bounding box will be placed  at
  1406. the current point.  The PostScript file must then contain (usually  near
  1407. the start) a comment of the form
  1408.  
  1409. %%BoundingBox: llx lly urx ury
  1410.  
  1411. specifying the bounding  box lower-left and  upper-right coordinates  in
  1412. standard PostScript units (1/72 inch).  Alternatively, if the comment
  1413.  
  1414. %%BoundingBox: (atend)
  1415.  
  1416. is found in  the file,  the last  1000 characters  of the  file will  be
  1417. searched to find a comment of the form:
  1418.  
  1419. %%BoundingBox: llx lly urx ury
  1420.  
  1421. If the  PostScript file  cannot  be opened,  or the  \special{}  command
  1422. string cannot be recognized, or  for relative positioning, the  bounding
  1423. box cannot be determined, a warning  message is issued and the  \special
  1424. command is ignored.
  1425.  
  1426. Otherwise, the section of the PostScript file between the comment lines
  1427.  
  1428. %begin(plot)
  1429. %end(plot)
  1430.  
  1431. is copied to the output file surrounded by
  1432.  
  1433. save
  1434. 300 72 div 300 72 div scale % revert to standard 1/72 inch units
  1435. (xcp(in 1/72in)-llx) (ycp(in 1/72in)-ury) translate  % if relative positioning
  1436. ...PostScript file contents...
  1437. restore
  1438.  
  1439. ***********************************************************************/
  1440.  
  1441.     clearerr(plotfp);        /* VMS sets the error flag unexpectedly */
  1442.  
  1443.     if (strncmp("overlay ",s,8) == 0)
  1444.     {
  1445.     k = 8;
  1446.     abspos = TRUE;
  1447.     }
  1448.     else if (strncmp("include ",s,8) == 0)
  1449.     {
  1450.     k = 8;
  1451.     abspos = FALSE;
  1452.     }
  1453.     else if (strncmp("insert ",s,7) == 0)
  1454.     {
  1455.     k = 7;
  1456.     abspos = FALSE;
  1457.     }
  1458.     else
  1459.     {
  1460.     NEWLINE(stderr);
  1461.     (void)fprintf(stderr,
  1462.         "[TeX \\special{%s} command not understood]",s);
  1463.     NEWLINE(stderr);
  1464.     (void)fprintf(stderr,"Expected one of:");
  1465.     NEWLINE(stderr);
  1466.     (void)fprintf(stderr,
  1467.         "\t\\special{overlay filename} [relative to page origin in ");
  1468.     (void)fprintf(stderr,
  1469.         "lower-left corner]");
  1470.     NEWLINE(stderr);
  1471.     (void)fprintf(stderr,"or");
  1472.     NEWLINE(stderr);
  1473.     (void)fprintf(stderr,
  1474.         "\t\\special{insert filename} [relative to current position]");
  1475.     NEWLINE(stderr);
  1476.     (void)fprintf(stderr,"or");
  1477.     NEWLINE(stderr);
  1478.     (void)fprintf(stderr,
  1479.         "\t\\special{include filename} [relative to current position]");
  1480.     NEWLINE(stderr);
  1481.     (void)fprintf(stderr,"\\special{%s} request ignored",s);
  1482.     NEWLINE(stderr);
  1483.     (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
  1484.     NEWLINE(stderr);
  1485.     return;
  1486.     }
  1487.     specfile = fopen(&s[k],"r");
  1488.     DEBUG_OPEN(specfile,&s[k],"r");
  1489.     if (specfile == (FILE *)NULL)
  1490.     {
  1491.     NEWLINE(stderr);
  1492.     (void)fprintf(stderr,
  1493.         "Open failure on \\special file [%s]",&s[k]);
  1494.     NEWLINE(stderr);
  1495.     (void)fprintf(stderr,"\\special{%s} request ignored",s);
  1496.     NEWLINE(stderr);
  1497.     (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
  1498.     NEWLINE(stderr);
  1499.     return;
  1500.     }
  1501.     if (abspos)
  1502.     {
  1503.     llx = lly = 0;
  1504.     urx = (72*17)/2;
  1505.     ury = 72*11;
  1506.     }
  1507.     else
  1508.     {
  1509.     llx = lly = urx = ury = -1;
  1510.     while (fgets(line,MAXLINE,specfile) != (char *)NULL)
  1511.     {
  1512.         llx = lly = urx = ury = -1;
  1513.         if (strncmp(line,"%%BoundingBox: (atend)",22) == 0)
  1514.         {    /* reposition to up to 1000 chars from end of file */
  1515.         (void)fstat(fileno(specfile),&statbuf);
  1516.         k = MIN(1000,(INT16)((long)statbuf.st_size-ftell(specfile)));
  1517.         if (k > 0)
  1518.             (void)fseek(specfile,(long)(-k),2);
  1519.         }
  1520.         else if (strncmp(line,"%%BoundingBox:",14) == 0)
  1521.         {
  1522.         k = (INT16)sscanf(line,
  1523.             "%%%%BoundingBox: %d %d %d %d",&llx,&lly,&urx,&ury);
  1524.         if (k == 4)
  1525.             break;        /* got %%BoundingBox */
  1526.         }
  1527.     }
  1528.     }
  1529.     if (ury == (-1))
  1530.     {
  1531.     NEWLINE(stderr);
  1532.     (void)fprintf(stderr,
  1533.         "Could not find PostScript %%%%BoundingBox command ");
  1534.     (void)fprintf(stderr,"needed to position plot on page");
  1535.     NEWLINE(stderr);
  1536.     (void)fprintf(stderr,"\\special{%s} request ignored",s);
  1537.     NEWLINE(stderr);
  1538.     (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
  1539.     NEWLINE(stderr);
  1540.     return;
  1541.     }
  1542.     NEWLINE(stderr);
  1543.     (void)fprintf(stderr,"\t[\\special{%s}] ",s);
  1544.     NEWLINE(stderr);
  1545.  
  1546.     OUT_IMMEDIATE;
  1547.     OUT_STR("save\n");        /* save current state */
  1548.  
  1549.     OUT_STR("300 72 div 300 72 div scale\n");    /* revert to standard units */
  1550.  
  1551.     if (!abspos)            /* move origin for include/insert */
  1552.     {
  1553.     moveto(hh,YSIZE-vv);        /* update current point */
  1554.     OUT_NUM((72*xcp)/300-llx);
  1555.     OUT_NUM((72*ycp)/300-ury);
  1556.     OUT_STR("translate\n");
  1557.     }
  1558.     (void)REWIND(specfile);        /* rewind file */
  1559.  
  1560.     while (fgets(line,MAXLINE,specfile) != (char *)NULL)
  1561.     {            /* search for %begin(plot) ... %end(plot) */
  1562.     if (strncmp(line,"%begin(plot)",12) == 0)
  1563.     {                /* copy until %end(plot) */
  1564.         while (fgets(line,MAXLINE,specfile) != (char *)NULL)
  1565.         {
  1566.         if (strncmp(line,"%end(plot)",10) == 0)
  1567.             break;
  1568.         OUTS(line);
  1569.         }
  1570.         break;
  1571.     }
  1572.     }
  1573.     OUT_STR("restore\n");
  1574.     (void)fclose(specfile);
  1575.     if (!quiet)
  1576.     {
  1577.     (void)fprintf(stderr," [OK]");
  1578.     NEWLINE(stderr);
  1579.     }
  1580.     if (DISKFULL(plotfp))
  1581.     (void)fatal("special():  Output error -- disk storage probably full");
  1582. }
  1583.  
  1584. #include "strchr.h"
  1585. #include "strcm2.h"
  1586. #include "strid2.h"
  1587. #include "strrchr.h"
  1588. #include "tctos.h"
  1589.  
  1590. /*-->textchr*/
  1591. /**********************************************************************/
  1592. /****************************** textchr *******************************/
  1593. /**********************************************************************/
  1594.  
  1595. void
  1596. textchr(c)                /* output character c */
  1597. register char c;
  1598. {
  1599.     char* psave;
  1600.  
  1601.     if (deferred)            /* deferred output */
  1602.     {
  1603.     *ptext++ = c;
  1604.     if (ptext >= (textbuf + MAXTEXT))
  1605.     {
  1606.         /* textbuf[] is full.  Backup to the last newline, output
  1607.            textbuf[] to that point, move the remainder to the
  1608.            start of textbf[], and resume character collection. */
  1609.         *ptext = '\0';    /* mark the end */
  1610.         psave = strrchr(textbuf,'\n'); /* find last line break */
  1611.         ptext = psave;    /* shorten buffer */
  1612.         *ptext = '\0';    /* mark the new end */
  1613.         textflush();    /* output the buffer */
  1614.         ++psave;        /* where we want to pick up remainder */
  1615.         OUT_FONTNAME;    /* make sure current font starts buffer */
  1616.         OUT_NL;
  1617.         OUT_NUM(xcp);    /* make sure current point is set too */
  1618.         OUT_NUM(ycp);
  1619.         OUT_STR("M\n");
  1620.  
  1621.         /* Since the above initial sequence requires at most 25
  1622.            characters, we should be safe here, since psave should
  1623.            be pointing near the end of textbuf[].  Nevertheless, we
  1624.            should watch for this time bomb, because someday someone
  1625.            might make MAXTEXT ridiculously small.  */
  1626.         if (ptext > psave)
  1627.             fatal("textchr(): internal error--textbuf[] too small");
  1628.  
  1629.         (void)strcpy(ptext,psave); /* move remainder to start */
  1630.         ptext = strchr(textbuf,'\0'); /* find the new end again */
  1631.     }
  1632.     }
  1633.     else                /* immediate output */
  1634.     {
  1635.  
  1636. #if    PS_SHORTLINES
  1637.         /***************************************************************
  1638.         Unfortunately, PostScript does allows only text bracketed  by ()
  1639.         to be broken across lines   by a   \newline sequence.  We   must
  1640.         therefore continue comments manually and break <...>  strings by
  1641.         a newline.  emitchar()  ensures that %  in () and non-bracketing
  1642.         () <> are encoded in octal, so as not to confuse us here.
  1643.         ***************************************************************/
  1644.  
  1645.     switch (c)        /* set flags for exiting environments */
  1646.     {
  1647.     case '\n':
  1648.         is_comment = FALSE;
  1649.         break;
  1650.  
  1651.         /* '<' editor balance */
  1652.     case '>':
  1653.         if (!is_comment)
  1654.             is_string = FALSE;
  1655.         break;
  1656.  
  1657.         /* '(' editor balance */
  1658.     case ')':
  1659.         if (!is_comment)
  1660.             is_text = FALSE;
  1661.         break;
  1662.     }
  1663.  
  1664.     if (out_width < (PS_MAXWIDTH-2)) /* 3 or more slots left on line */
  1665.     {
  1666.         switch (c)
  1667.         {
  1668.         case '\n':
  1669.         NEWLINE(plotfp);
  1670.             out_width = 0;
  1671.         break;
  1672.  
  1673.         default:
  1674.         OUTC(c);
  1675.             out_width++;
  1676.         break;
  1677.         }
  1678.     }
  1679.     else if (out_width == (PS_MAXWIDTH-2)) /* 2 slots left on line */
  1680.     {
  1681.         if (is_comment)
  1682.         {
  1683.         OUTC(c);
  1684.         out_width++;
  1685.         }
  1686.         else        /* not comment */
  1687.         {
  1688.         switch (c)
  1689.         {
  1690.         case '(':    /* special \newline inside (...text...) */
  1691.             OUTC(c);
  1692.             OUTC('\\');
  1693.             NEWLINE(plotfp);
  1694.             out_width = 0;
  1695.             break;
  1696.  
  1697.         case '\n':        /* ordinary newline */
  1698.             NEWLINE(plotfp);
  1699.             out_width = 0;
  1700.             break;
  1701.  
  1702.         default:        /* else just output the character */
  1703.             OUTC(c);
  1704.             out_width++;
  1705.             break;
  1706.         }        /* end switch */
  1707.         }            /* end if (is_comment) */
  1708.     }
  1709.     else            /* at most 1 slot left */
  1710.     {
  1711.         if (is_comment)
  1712.         {            /* make special continued comment */
  1713.         OUTC('-');
  1714.         NEWLINE(plotfp);
  1715.         OUTS("%-");
  1716.         OUTC(c);
  1717.         out_width = 3;
  1718.         }
  1719.         else        /* not comment */
  1720.         {
  1721.         switch (c)
  1722.         {
  1723.         case '%':    /* start newline for comment or (...text...) */
  1724.         case '(':
  1725.             NEWLINE(plotfp);
  1726.             OUTC(c);
  1727.             out_width = 1;
  1728.             break;
  1729.  
  1730.         case ')':        /* follow (...text...) with newline */
  1731.         case '<':        /* newline inside <...text...> okay */
  1732.         case '>':        /* follow <...text...> with newline */
  1733.             OUTC(c);
  1734.             NEWLINE(plotfp);
  1735.             out_width = 0;
  1736.             break;
  1737.  
  1738.         case ' ':        /* change trailing space to newline */
  1739.         case '\n':        /* newline */
  1740.             NEWLINE(plotfp);
  1741.             out_width = 0;
  1742.             break;
  1743.  
  1744.         default:
  1745.             if (is_text) /* \newline continuation in (...text...) */
  1746.             {
  1747.             OUTC('\\');
  1748.             NEWLINE(plotfp);
  1749.             OUTC(c);
  1750.             out_width = 1;
  1751.             }
  1752.             else if (is_string)    /* newline inside <...text...> okay */
  1753.             {
  1754.             OUTC(c);
  1755.             NEWLINE(plotfp);
  1756.             out_width = 0;
  1757.             }
  1758.             else    /* cannot break at this point, sigh... */
  1759.             {
  1760.             OUTC(c);
  1761.             out_width++;
  1762.             }
  1763.             break;
  1764.         }        /* end switch */
  1765.         }            /* end if (is_comment) */
  1766.     }
  1767.  
  1768.     switch (c)        /* set flags for entering environments */
  1769.     {
  1770.     case '%':
  1771.         is_comment = TRUE;
  1772.         break;
  1773.  
  1774.     case '<':
  1775.         if (!is_comment)
  1776.             is_string = TRUE;
  1777.         break;
  1778.  
  1779.     case '(':
  1780.         if (!is_comment)
  1781.             is_text = TRUE;
  1782.         break;
  1783.     }
  1784. #else /* NOT PS_SHORTLINES */
  1785.     OUTC(c);
  1786. #endif /* PS_SHORTLINES */
  1787.  
  1788.     }                /* endif deferred/immediate */
  1789. }
  1790.  
  1791. /*-->textflush*/
  1792. /**********************************************************************/
  1793. /***************************** textflush ******************************/
  1794. /**********************************************************************/
  1795.  
  1796. void
  1797. textflush()                /* flush current textbuf[] to output */
  1798. {
  1799.  
  1800. #if    PS_SHORTLINES
  1801.     register char* pbreak;        /* point to character before */
  1802.                     /* which we can insert a line break */
  1803.     char linebuf[PS_MAXWIDTH+1];    /* buffer for output line */
  1804.     register INT16 k;            /* index in linebuf[] */
  1805.     register INT16 kbreak;        /* break index in linebuf[] */
  1806.                     /* corresponding to pbreak */
  1807. #endif /* PS_SHORTLINES */
  1808.  
  1809.     /* Wrap the current textbuf[] contents with save/restore, but
  1810.        preserve the current point and font. */
  1811.     if (ptext > textbuf)    /* make sure textbuf[] is not empty */
  1812.     {
  1813.  
  1814. #if    PS_SHORTLINES
  1815.     if (out_width > 0)    /* want TB ... TE on separate lines */
  1816.         NEWLINE(plotfp);
  1817. #endif /* PS_SHORTLINES */
  1818.  
  1819.     OUTS("TB");
  1820.     NEWLINE(plotfp);
  1821.  
  1822.     *ptext = '\0';        /* terminate current textbuf[] */
  1823.  
  1824. #if    PS_SHORTLINES
  1825.     ptext = textbuf;
  1826.     pbreak = ptext;
  1827.     k = 0;
  1828.     kbreak = 0;
  1829.     while (*ptext)
  1830.     {
  1831.         if (k >= PS_MAXWIDTH)
  1832.         {
  1833.         if (kbreak > 0)
  1834.         {
  1835.             k = kbreak;
  1836.             ptext = pbreak;
  1837.         }
  1838.         while ((k > 0) && (linebuf[k-1] == ' '))
  1839.             k--;        /* trim trailing space */
  1840.         linebuf[k] = '\0';
  1841.         OUTS(linebuf);
  1842.         k = 0;
  1843.         if ((kbreak > 0) || (*(ptext+1) == '\0'))
  1844.             NEWLINE(plotfp);
  1845.         }
  1846.         if ((*ptext == '\n') && (*(ptext+1) == '('))
  1847.             ptext++;        /* squeeze out useless newline */
  1848.         if (*ptext == '\n')
  1849.             *ptext = ' ';        /* change newline to blank */
  1850.         if ((k == 0) && (*ptext == ' '))
  1851.         /* NO-OP */;            /* don't save leading space */
  1852.         else
  1853.             linebuf[k++] = *ptext;
  1854.         if ((*ptext == ' ') || (*ptext == '('))
  1855.         {
  1856.         kbreak = k - 1;
  1857.             pbreak = ptext;
  1858.         }
  1859.         else if (*ptext == ')')
  1860.         {
  1861.         kbreak = k;
  1862.             pbreak = ptext + 1;
  1863.         }
  1864.         ptext++;
  1865.     }
  1866.     if (k > 0)
  1867.     {
  1868.         while ((k > 0) && (linebuf[k-1] == ' '))
  1869.             k--;        /* trim trailing space */
  1870.         linebuf[k] = '\0';
  1871.         OUTS(linebuf);
  1872.         NEWLINE(plotfp);
  1873.     }
  1874.     out_width = 0;
  1875. #else /* NOT PS_SHORTLINES */
  1876.     OUTS(textbuf);
  1877.     NEWLINE(plotfp);
  1878. #endif /* PS_SHORTLINES */
  1879.  
  1880.     OUTS("TE");
  1881.     NEWLINE(plotfp);
  1882.  
  1883.     ptext = textbuf;
  1884.     }
  1885. }
  1886.  
  1887. /*-->textnum*/
  1888. /**********************************************************************/
  1889. /****************************** textnum *******************************/
  1890. /**********************************************************************/
  1891.  
  1892. void
  1893. textnum(n)            /* output number with one trailing space */
  1894. long n;                /* the number */
  1895. {
  1896.     char digits[11];
  1897.  
  1898.     (void)sprintf(digits,"%ld",n);
  1899.     textstr(digits);
  1900.  
  1901. #if    PS_SHORTLINES
  1902.     if (!deferred && !is_comment && (out_width == 0))
  1903.     /* NO-OP */;        /* omit space at beginning of line */
  1904.     else
  1905.     textchr(' ');
  1906.  
  1907. #else /* NOT PS_SHORTLINES */
  1908.     textchr(' ');
  1909. #endif /* PS_SHORTLINES */
  1910.  
  1911. }
  1912.  
  1913.  
  1914.  
  1915. /*-->textstr*/
  1916. /**********************************************************************/
  1917. /****************************** textstr *******************************/
  1918. /**********************************************************************/
  1919.  
  1920. void
  1921. textstr(s)                /* output string s[] */
  1922. register char* s;
  1923. {
  1924.  
  1925. #if    PS_SHORTLINES
  1926.     if (!deferred && !is_comment && ((out_width + strlen(s)) > PS_MAXWIDTH))
  1927.         OUT_NL;
  1928. #endif /* PS_SHORTLINES */
  1929.  
  1930.     for (; *s; ++s)
  1931.         textchr(*s);
  1932. }
  1933.  
  1934. #include "usage.h"
  1935. #include "warning.h"
  1936.